﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

namespace Mirkuz.PowerManagement
{
    public enum SystemStates
    {
        Resuming,Unattended,ScreenOFF,On,Off,Suspend,Unknown
    }

    /// <summary>
    /// consente di eseguire una applicazione in modalità unattended
    /// </summary>
    public class UnattendedManager : IDisposable
    {
        IntPtr _msgqueue = IntPtr.Zero;
        Thread _pmthread = null;
        bool done = false;

        public SystemStates SystemState= SystemStates.Unknown;

        public UnattendedManager()
        {
            MsgQOptions options = new MsgQOptions();

            options.dwFlags = 0;
            options.dwMaxMessages = 20;
            options.cbMaxMessage = 10000;
            options.bReadAccess = true;
            options.dwSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(options);

            _msgqueue = PMAPI.CreateMsgQueue("mirkuz.pmqueue", ref options);
            PMAPI.RequestPowerNotifications(_msgqueue, (uint)(PowerEventType.PBT_TRANSITION | PowerEventType.PBT_POWERINFOCHANGE));

        }

        public void RequestUnattendedMode()
        {
            if (_pmthread==null)
            {
                _pmthread = new Thread(new ThreadStart(DoWork));
                _pmthread.Start();

                //richiedo l'ingresso in stato unattended
                PMAPI.PowerPolicyNotify((uint)PowerPolicyNotifyMessages.PPN_UNATTENDEDMODE, 1);               
            }
        }

        public void ReleaseUnattendedMode()
        {
            if (_pmthread != null)
            {
                done = true;
                _pmthread.Abort();
                _pmthread = null;

                //richiedo l'uscita dallo stato unattended
                PMAPI.PowerPolicyNotify((uint)PowerPolicyNotifyMessages.PPN_UNATTENDEDMODE, 0);
            }
        }

        private void DoWork()
        {           
            try
            {
                while (!done)
                {
                    uint res = 0;
                    res = PMAPI.WaitForSingleObject(_msgqueue, 1000);
                    if (res == 0)
                    {
                        byte[] buf = new byte[40];
           
                        
                        uint nRead = 0, flags = 0;
                        if (PMAPI.ReadMsgQueue(_msgqueue,
                                            buf,
                                            (uint)buf.Length,
                                            ref nRead, 1000, ref flags))
                        {
                            try 
                            {
                                POWER_BROADCAST pbmessage = new POWER_BROADCAST(buf);                               
                                  
                                //se sto cambiando stato
                                if (pbmessage.Message == PowerEventType.PBT_TRANSITION)
                                {
                                    SystemState= SystemStates.Unknown;

                                    if (pbmessage.SystemPowerState.ToLower().Contains("screenoff"))
                                        SystemState = SystemStates.ScreenOFF;

                                    if (pbmessage.SystemPowerState.ToLower().Contains("on"))
                                        SystemState = SystemStates.On;

                                    if (pbmessage.SystemPowerState.ToLower().Contains("suspend"))
                                        SystemState = SystemStates.Suspend;              

                                    if (pbmessage.SystemPowerState.ToLower().Contains("unattended"))
                                    {
                                        SystemState = SystemStates.Unattended;
                                        //sono passato in unattended e mantengo
                                        PMAPI.SystemIdleTimerReset();

                                    }
                                    if (pbmessage.SystemPowerState.ToLower().Contains("resuming"))
                                    {
                                        SystemState = SystemStates.Resuming;
                                        PMAPI.PowerPolicyNotify((uint)PowerPolicyNotifyMessages.PPN_UNATTENDEDMODE, 1);
                                    }              
                                }
                            }
                            catch { }
                        }

                    }
                }
            }
            catch { }
        }

        #region IDisposable Members

        public void Dispose()
        {
            try
            {
                if (_pmthread != null)
                {
                    _pmthread.Abort();
                    _pmthread = null;
                }
            }
            catch { }
        }

        #endregion
    }
    
		
}
